package utils

import (
	"encoding/json"
	"fmt"
	"math"
	"math/rand"
	"os"
	"strings"
	"time"
	"wx_order_server/internal/svc"

	"github.com/bwmarrin/snowflake"
	"github.com/golang-jwt/jwt/v4"
	"github.com/nleeper/goment"

	"golang.org/x/crypto/bcrypt"
)

type ReturnStruct[T any] struct {
	Code int    `json:"code"`
	Msg  string `json:"message"`
	Data T      `json:"data"`
}

type ReqTableStruct[T any] struct {
	Page     int `json:"page"`
	PageSize int `json:"page_size"`
	Total    int `json:"total"`
	List     T   `json:"list"`
}

func FuncRunTime(fn func()) {
	startTime := time.Now().UnixNano()
	fn()
	endTime := time.Now().UnixNano()
	Milliseconds := float64((endTime - startTime) / 1e6)
	fmt.Println("计时", Milliseconds, "毫秒")
}

func ReturnRsOk[T any](code int, msg string, data T) *ReturnStruct[T] {

	if msg == "" {
		msg = "请求成功"
	}

	return &ReturnStruct[T]{
		Code: code,
		Msg:  msg,
		Data: data,
	}
}

func ReturnRsError(code int, msg string, data string) ReturnStruct[string] {
	if code == -1 {
		code = 10001
	}

	if msg == "" {
		msg = "请求失败"
	}

	return ReturnStruct[string]{
		Code: code,
		Msg:  msg,
		Data: data,
	}
}

// CheckToken
// 校验token是否有效 返回参数
func CheckToken(tokenString string) (id float64, err error) {
	token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
		// Don't forget to validate the alg is what you expect:
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
		}
		// hmacSampleSecret is a []byte containing your secret, e.g. []byte("my_secret_key")
		return []byte("zeroapps"), nil
	})
	if err != nil {
		//logs.Error(err)
		return 0, err
	}
	// token.Valid里已经包含了过期判断
	if token != nil && token.Valid {
		claims, _ := token.Claims.(jwt.MapClaims)
		id = claims["userId"].(float64)
	}

	return id, err
}

func StringToInt(str string) int {
	var result int
	for _, v := range str {
		result = result*10 + int(v-'0')
	}
	return result
}

func StringToIntArr(str []string) []int {
	var result []int
	for _, v := range str {
		result = append(result, StringToInt(v))
	}
	return result
}

// Password 密码加密
func Password(plainpwd string) string {
	//谷歌的加密包
	hash, err := bcrypt.GenerateFromPassword([]byte(plainpwd), bcrypt.DefaultCost) //加密处理
	if err != nil {
		fmt.Println(err)
	}
	encodePWD := string(hash) // 保存在数据库的密码，虽然每次生成都不同，只需保存一份即可
	return encodePWD
}

// CheckPassword 密码校验
func CheckPassword(plainpwd, cryptedpwd string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(cryptedpwd), []byte(plainpwd)) //验证（对比）
	return err == nil
}

func GetSnowflakeId() int64 {
	node, _ := snowflake.NewNode(1)

	id := node.Generate().Int64()

	return id
}

func CreateTableData[T any](page int, pageSize int, total int, list T) ReqTableStruct[T] {
	return ReqTableStruct[T]{
		Page:     page,
		PageSize: pageSize,
		Total:    total,
		List:     list,
	}
}

func WirteToJSONFile(data interface{}, fileName string) {
	// 创建文件
	file, e := os.Create(fileName)
	if e != nil {
		fmt.Println(e)
		return
	}
	defer file.Close()

	// 序列化json
	dataJson, _ := json.Marshal(data)

	// 写入文件
	_, _ = file.Write(dataJson)
}

const timezone = "Asia/Shanghai"

func TimeFormat(date time.Time, pattern string) string {
	location, err := time.LoadLocation(timezone)
	if err != nil {
		location = time.FixedZone("CST", 8*3600) //替换上海时区方式
	}
	date.In(location)
	return date.Format(pattern)
}

func GetLoc() *time.Location {
	loc, err := time.LoadLocation("Asia/Shanghai")
	if err != nil {
		loc = time.FixedZone("CST", 8*3600)
	}
	return loc
}

func InTime(startTime string, endTime string) bool {
	var LOC = GetLoc()

	nowUnix := time.Now().Unix()
	startTimeStr := time.Now().Format("2006-01-02") + " " + startTime
	endTimeStr := time.Now().Format("2006-01-02") + " " + endTime
	startTimeT, _ := time.ParseInLocation("2006-01-02 15:04", startTimeStr, LOC)
	endTimeT, _ := time.ParseInLocation("2006-01-02 15:04", endTimeStr, LOC)
	startTimeUnix := startTimeT.Unix()
	endTimeUnix := endTimeT.Unix()

	fmt.Println(nowUnix, startTimeUnix, endTimeUnix)

	return nowUnix < endTimeUnix && nowUnix > startTimeUnix
}

func GetSendTimeArr(sendTimes, sendDays, startTime, endTime int) []string {
	var sendTimeArr []string
	rand.Seed(time.Now().UnixNano())

	for i := 0; i < sendTimes; i++ {
		// 随机生成 1 - sendDays 天
		randDay := rand.Intn(sendDays) + 1
		// 生成时间
		gN, _ := goment.New()
		sendDayStr := gN.Add(randDay-1, "days").Format("YYYY-MM-DD")

		// 随机生成时间 8 - 22
		randTime := rand.Intn(endTime-startTime) + startTime
		// 随机生成 10 - 59
		randMinute := rand.Intn(50) + 10

		// 已现在时间为基准，生成时间
		sendTimeStr := sendDayStr + fmt.Sprintf(" %d:%d", randTime, randMinute)
		debugStr := fmt.Sprintf("生成时间：%s", sendTimeStr)
		fmt.Println(debugStr)
		sendTimeArr = append(sendTimeArr, sendTimeStr)
	}

	return sendTimeArr
}

func StrToInt(str string) int {
	var result int
	for _, v := range str {
		result = result*10 + int(v-'0')
	}
	return result
}

func RSaveLimit(key string, data interface{}, limitDay int) {
	// 序列化json
	dataJson, _ := json.Marshal(data)
	_ = svc.GlobalRedis.Setex(key, string(dataJson), limitDay)
}

func GetRedisKey(key string) string {
	// 去掉空格
	return "mainServer:" + strings.ReplaceAll(key, " ", "")
}

func RGet[T any](key string) (T, error) {
	var data T
	jsonVal, err := svc.GlobalRedis.Get(key)
	_ = json.Unmarshal([]byte(jsonVal), &data)

	return data, err
}

func RDel(key string) {
	_, _ = svc.GlobalRedis.Del(key)
}

// InTimeTwoMinutes 判断时间是否在现在时间的2分钟之内
func InTimeTwoMinutes(startTime string) bool {
	var LOC = GetLoc()

	nowUnix := time.Now().Unix()
	fmt.Println("当前时间", startTime)
	startTimeStr, _ := time.ParseInLocation("2006-01-02 15:04", startTime, LOC)
	startTimeUnix := startTimeStr.Unix()

	// 格式化输出文本
	debugStr := fmt.Sprintf("当前时间：%d, 发送时间：%d, 时间差：%f, 发送时间str: %s", nowUnix, startTimeUnix, float64(nowUnix-startTimeUnix), startTimeStr)
	fmt.Println(debugStr)

	return math.Abs(float64(nowUnix-startTimeUnix)) < 120
}
